package cn.fengLone.pay.util.RSA;

import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Iterator;
import java.util.Map;

import javax.crypto.Cipher;

/**
 * 
 * @description 商户数据加密解密工具类
 * 
 * @compny 深圳风轮科技有限公司
 * 
 * @author Guo PengFei
 * 
 * @date 2017-11-19
 * 
 * @version V1.0
 *
 */
public class ClientRSAUtil {
	/**
	 * 加密算法RSA
	 */
    public static final String KEY_ALGORITHM = "RSA";
    
    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;
    
    /** *//**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;

    
    /** *//**
     * <P>
     * 私钥解密
     * </p>
     * 
     * @param encryptedData 已加密数据
     * @param privateKey 私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static String decryptByPrivateKey(String encryptedData, String privateKey)
            throws Exception {
    	byte [] tempData = stringToByte(encryptedData);
    	byte [] target = decryptByPrivateKey(tempData, privateKey);
    	return new String(target);
    }
    
    /**
     * 把16进制字符串转换成字节数组
     * @param hexString
     * @return byte[]
     */
    private static byte[] stringToByte(String hex) {
    	String [] temp1 = hex.split(",");
    	int len = temp1.length;
    	byte[] result = new byte[len];
    	for (int i = 0;i<len;i++) {
    		byte a = new Byte(temp1[i]);
			result[i] = a;
		}
    	return result;
    }
    /** *//**
     * <P>
     * 私钥解密
     * </p>
     * 
     * @param encryptedData 已加密数据
     * @param privateKey 私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)
            throws Exception {
        byte[] keyBytes = Base64Utils.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

    
    
    
    
	  /**
     * 私钥加密 
     * @param data 源数据
     * @param privateKey 私钥(BASE64编码)
     * @throws Exception
     */
    public static String encryptByPrivateKey(String data, String privateKey)
            throws Exception {
    	byte [] sign_val = data.getBytes();
    	
    	byte [] decode_val = encryptByPrivateKey(sign_val, privateKey);
    	return byteToString(decode_val);
    }
    
	  /**
     * 私钥加密 
     * @param data 源数据
     * @param privateKey 私钥(BASE64编码)
     * @throws Exception
     */
    public static String encryptByPrivateKey(Map<String, String> paramMap, String privateKey)
            throws Exception {
    	String data = mapToString(paramMap);
    	byte [] sign_val = data.getBytes();
    	
    	byte [] decode_val = encryptByPrivateKey(sign_val, privateKey);
    	return byteToString(decode_val);
    }
    /**
     * 数组转成十六进制字符串
     * @param byte[]
     * @return HexString
     */
    private static String byteToString(byte[] b){
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < b.length; ++i){
            buffer.append(String.valueOf(b[i])).append(",");
        }
        return buffer.toString().substring(0,buffer.length()-1);
    }
   
    
    /** *//**
     * <p>
     * 私钥加密
     * </p>
     * 
     * @param data 源数据
     * @param privateKey 私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    private static byte[] encryptByPrivateKey(byte[] data, String privateKey)
            throws Exception {
        byte[] keyBytes = Base64Utils.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }

    /**
     * 将参数集合转为String
     * @param paramMap 要转换的数据源集合
     * @return
     */
    private static String mapToString(Map<String, String> paramMap){
    	StringBuffer buffer = new StringBuffer();
    	buffer.append("{");
    	Iterator<String> iterator = paramMap.keySet().iterator();
    	while (iterator.hasNext()) {
    		String key = iterator.next();
    		String value = paramMap.get(key);
    		buffer.append("'").append(key).append("':'").append(value).append("',");
    	}
    	String result = buffer.substring(0,buffer.length()-1)+"}";
    	return result;
    }
}
